package org.activequant.core.util;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import org.activequant.core.domainmodel.marketscanner.MarketScan;
import org.activequant.core.domainmodel.marketscanner.MarketScanSeries;
import org.activequant.core.types.TimeStamp;
import org.activequant.util.exceptions.ValueNotFoundException;

/**
* A MarketScanSeries, TimeSeries and ArrayList subclass. Holds the following associated variable:
* <ul>
* <li>cache(TreeMap&lt;TimeStamp,MarketScan&gt;)</li>
* </ul>
*/
public class MarketScanSeriesHash extends MarketScanSeries {

	private static final long serialVersionUID = 5254689954795874715L;
	/**
	 * private TreeMap&lt;TimeStamp,MarketScan&gt; cache = new TreeMap&lt;TimeStamp,MarketScan&gt;();
	 */
	private TreeMap<TimeStamp, MarketScan> cache = new TreeMap<TimeStamp, MarketScan>();
	/**
	 * 
	 * @param marketScanSeries
	 */
	public MarketScanSeriesHash(MarketScanSeries marketScanSeries) {
		super(marketScanSeries);
		rebuildCache();
	}
	/**
	 * clears and then re-fills the associated cache(TreeMap&lt;TimeStamp,MarketScan&gt;) using the MarketScan elements of this MarketScanSeriesHash(CandleSeries and ArrayList subclass) as values and their
	 * timeStamp(TimeStamp)'s as the keys.
	 */
	private void rebuildCache() {
		cache.clear();
		for(MarketScan marketScan: this) {
			cache.put(marketScan.getTimeStamp(), marketScan);
		}
	}
	/**
	 * returns the timeStamp(TimeStamp) of the Candle element at the given i(int) position in this MarketScanSeriesHash(MarketScanSeries and ArrayList subclass)
	 * @param i
	 * @return
	 */
	public TimeStamp getTimeStamp(int i) {
		return get(i).getTimeStamp();
	}
	/**
	 * returns a MarketScanSeries(ArrayList) holding the MarketScan objects (from the MarketScan values in the associated cache(TreeMap&lt;TimeStamp,MarketScan&gt;)) 
	 * whose timeStamp(TimeStamp)'s is in the given start-end(TimeStamp) interval
	 */
	public MarketScanSeries getTimeFrame(TimeStamp start, TimeStamp end) {        
	    SortedMap<TimeStamp, MarketScan> subMap = cache.subMap(start, end);
	    MarketScanSeries marketScanSeries = new MarketScanSeries();
	    marketScanSeries.addAll(subMap.values());        
	    return marketScanSeries;
	}
	/**
	 * returns whether the associated cache(TreeMap&lt;TimeStamp,MarketScan&gt;) contains the given date(TimeStamp) as key
	 */
	public boolean containsTimeStamp(TimeStamp date) {
		return cache.containsKey(date);
	}
	/**
	 * returns the MarketScan mapped under the given date(TimeStamp) in the associated cache(TreeMap&lt;TimeStamp,MarketScan&gt;)
	 * @param date
	 * @return
	 */
	public MarketScan getMarketScanByTimeStamp(TimeStamp date) {
		return cache.get(date);
	}
	/**
	 * returns the position of the given date(TimeStamp) among the TimeStamp keys in the associated cache(TreeMap&lt;TimeStamp,MarketScan&gt;)
	 */
	public int getTimeStampPosition(TimeStamp date) throws ValueNotFoundException {
		List<TimeStamp> dates = new LinkedList<TimeStamp>();
		dates.addAll(cache.keySet());
		int pos = Collections.binarySearch(dates, date);
		if (pos < 0)
			throw new ValueNotFoundException("Cannot find value for date '" + date + "'.");
		return pos;
	}
}